package com.hello.web.service.permission;


import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hello.common.utils.Response;
import com.hello.web.domain.bo.permission.PermissionQueryBO;
import com.hello.web.domain.bo.permission.PermissionUpdateBO;
import com.hello.web.domain.entity.PermissionDO;
import com.hello.web.domain.entity.RolePermissionDO;
import com.hello.web.domain.entity.UserRoleDO;
import com.hello.web.domain.mapper.PermissionMapper;
import com.hello.web.domain.mapper.RolePermissionMapper;
import com.hello.web.domain.mapper.UserRoleMapper;
import com.hello.web.domain.vo.permission.PermissionMenuVO;
import com.hello.web.domain.vo.permission.PermissionRoleTreeVO;
import com.hello.web.domain.vo.permission.PermissionTreeVO;
import com.hello.web.domain.vo.permission.PermissionVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class PermissionService {

    private final UserRoleMapper userRoleMapper;
    private final PermissionMapper permissionMapper;
    private final RolePermissionMapper rolePermissionMapper;


    public Response queryPermissionByRoleId(PermissionQueryBO bo) {
        List<RolePermissionDO> rolePermissionList = rolePermissionMapper.selectList(
                new LambdaQueryWrapper<RolePermissionDO>()
                        .eq(RolePermissionDO::getRoleId, bo.getRoleId())
        );
        List<Long> permissionIds = rolePermissionList.stream().map(RolePermissionDO::getPermissionId).collect(Collectors.toList());
        if (permissionIds.isEmpty()) {
            return Response.success(new ArrayList<>());
        }
        List<PermissionDO> permissionList = permissionMapper.selectBatchIds(permissionIds);
        List<PermissionVO> permissionVOS = permissionList.stream().map(
                        permissionDO -> PermissionVO.builder()
                                .id(permissionDO.getId())
                                .name(permissionDO.getName())
                                .icon(permissionDO.getIcon())
                                .path(permissionDO.getPath())
                                .parentId(permissionDO.getParentId())
                                .type(permissionDO.getType())
                                .checkValue(permissionDO.getCheckValue())
                                .sort(permissionDO.getSort())
                                .build())
                .collect(Collectors.toList());
        permissionVOS.sort(Comparator.comparing(PermissionVO::getSort));
        return Response.success(permissionVOS);
    }

    public Response queryPermissionList() {
        List<PermissionDO> permissionList = permissionMapper.selectList(null);
        List<PermissionVO> permissionVOS = permissionList.stream().map(
                        permissionDO -> PermissionVO.builder()
                                .id(permissionDO.getId())
                                .name(permissionDO.getName())
                                .icon(permissionDO.getIcon())
                                .path(permissionDO.getPath())
                                .parentId(permissionDO.getParentId())
                                .type(permissionDO.getType())
                                .checkValue(permissionDO.getCheckValue())
                                .sort(permissionDO.getSort())
                                .build())
                .collect(Collectors.toList());
        permissionVOS.sort(Comparator.comparing(PermissionVO::getSort));
        return Response.success(permissionVOS);
    }

    public Response updatePermissionByRoleId(PermissionUpdateBO bo) {
        rolePermissionMapper.delete(
                new LambdaQueryWrapper<RolePermissionDO>()
                        .eq(RolePermissionDO::getRoleId, bo.getRoleId())
        );
        bo.getPermissionIdList().forEach(
                permissionId -> {
                    RolePermissionDO rolePermissionDO = RolePermissionDO.builder()
                            .roleId(bo.getRoleId())
                            .permissionId(permissionId)
                            .build();
                    rolePermissionMapper.insert(rolePermissionDO);
                }
        );
        return Response.success();
    }

    public Response queryMenuList() {
        ArrayList<PermissionMenuVO> resultVO = new ArrayList<>();

        UserRoleDO userRoleDO = userRoleMapper.selectOne(
                new LambdaQueryWrapper<UserRoleDO>()
                        .eq(UserRoleDO::getUserId, StpUtil.getLoginIdAsLong())
                        .last("limit 1")
        );
        if (userRoleDO == null) {
            return Response.success(resultVO);
        }
        List<Long> permissionIds = rolePermissionMapper.selectList(
                        new LambdaQueryWrapper<RolePermissionDO>()
                                .eq(RolePermissionDO::getRoleId, userRoleDO.getRoleId())
                ).stream()
                .map(RolePermissionDO::getPermissionId)
                .collect(Collectors.toList());

        if (permissionIds.isEmpty()) return Response.success(resultVO);

        List<PermissionDO> permissionList = permissionMapper.selectBatchIds(permissionIds);
        List<PermissionDO> menuList = permissionList.stream().filter(permissionDO -> permissionDO.getType() == 1).sorted(Comparator.comparing(PermissionDO::getSort)).collect(Collectors.toList());
        menuList.forEach(menu -> {
            List<PermissionDO> children = permissionList
                    .stream()
                    .filter(item -> item.getParentId() == menu.getId())
                    .collect(Collectors.toList());
            List<PermissionMenuVO> childMenuList = children.stream().sorted(Comparator.comparing(PermissionDO::getSort)).map(
                    item -> PermissionMenuVO.builder()
                            .name(item.getName())
                            .icon(item.getIcon())
                            .path(item.getPath())
                            .build()
            ).collect(Collectors.toList());
            PermissionMenuVO permissionMenuVO = PermissionMenuVO.builder()
                    .name(menu.getName())
                    .icon(menu.getIcon())
                    .path(menu.getPath())
                    .children(childMenuList.isEmpty() ? null : childMenuList)
                    .build();
            resultVO.add(permissionMenuVO);
        });
        return Response.success(resultVO);
    }

    public Response queryTreeList() {
        List<PermissionDO> permissionList = permissionMapper.selectList(null);
        List<PermissionDO> nodeList = permissionList.stream().filter(permissionDO -> permissionDO.getType() == 1).collect(Collectors.toList());
        List<PermissionTreeVO> permissionTreeVOS = nodeList.stream().map(
                        permissionDO -> PermissionTreeVO.builder()
                                .id(permissionDO.getId())
                                .label(permissionDO.getName())
                                .children(null)
                                .build())
                .collect(Collectors.toList());
        for (PermissionTreeVO permissionTreeVO : permissionTreeVOS) {
            List<PermissionTreeVO> children = permissionList.stream().filter(permissionDO -> permissionDO.getParentId() == permissionTreeVO.getId()).map(
                            permissionDO -> PermissionTreeVO.builder()
                                    .id(permissionDO.getId())
                                    .label(permissionDO.getName())
                                    .children(null)
                                    .build())
                    .collect(Collectors.toList());
            permissionTreeVO.setChildren(children.isEmpty() ? null : children);
        }
        return Response.success(permissionTreeVOS);
    }

    public Response queryRoleIdTreeList(PermissionQueryBO bo) {
        List<PermissionRoleTreeVO> resultVO = new ArrayList<>();

        List<Long> permissionIds = rolePermissionMapper.selectList(
                        new LambdaQueryWrapper<RolePermissionDO>()
                                .eq(RolePermissionDO::getRoleId, bo.getRoleId())
                ).stream()
                .map(RolePermissionDO::getPermissionId)
                .collect(Collectors.toList());
        if (permissionIds.isEmpty()) return Response.success(resultVO);
        List<PermissionDO> permissionList = permissionMapper.selectBatchIds(permissionIds);
        resultVO = permissionList.stream().map(
                permissionDO -> PermissionRoleTreeVO.builder()
                        .id(permissionDO.getId())
                        .label(permissionDO.getName())
                        .build()
        ).collect(Collectors.toList());

        return Response.success(resultVO);
    }
}
